//@author A0098733R

package taskit.logic;

import java.util.*;

import taskit.datastructures.Date;
import taskit.datastructures.Deadline;
import taskit.datastructures.Floating;
import taskit.datastructures.ITaskItObject;
import taskit.storage.Data;

public class ParserReturnObject implements ITaskItObject {

	public static final int ACTION_NULL = 0, ACTION_UPDATE_ALL = 1,
			ACTION_UPDATE_DAS = 2, ACTION_UPDATE_FT = 3,
			ACTION_CUSTOM_DATES = 4;

	public static final int STATUS_SHOW_CURRENT = 0, STATUS_SHOW_ARCHIVE = 1,
			STATUS_SHOW_DATE = 2, STATUS_SHOW_DATE_RANGE = 3,
			STATUS_SHOW_SEARCH = 4, STATUS_SHOW_SEARCH_ARCHIVE = 5, 
			STATUS_SHOW_SEARCH_TAGS = 6;

	private static boolean floatingListChanged;
	private static boolean deadlineListChanged;
	private static int actionCode = ACTION_UPDATE_ALL;
	private static int statusCode = STATUS_SHOW_CURRENT;
	private static int actionCodeContext;
	private static int statusCodeContext;
	private static Date date, start, end;
	private static Data internalData;
	private static LinkedList<Deadline> deadlinesAndSchedules = new LinkedList<Deadline>();
	private static LinkedList<Floating> floatingTasks = new LinkedList<Floating>();
	private static String searchString;
	private static Queue<String> messages = new LinkedList<String>();

	/**
	 * Retrieves the number of deadlines and schedules in the
	 * DeadlinesAndSchedules panel that should be on the GUI
	 * 
	 * @return integer denoting number of tasks on list
	 */
	public static int getLengthDaS() {
		return deadlinesAndSchedules.size();
	}

	/**
	 * Retrieves the number of floating tasks in the floating task panel that should be on
	 * the GUI
	 * 
	 * @return integer denoting number of tasks in the todo list
	 */
	public static int getLengthFT() {
		return floatingTasks.size();
	}

	/**
	 * Retrieves the specified <b>index</b> in the deadlines and schedules list
	 * 
	 * @param index
	 *            index of item from deadlinesAndSchedules list
	 * @return a Deadline instance from the list
	 * @throws Exception
	 */
	public static Deadline getDaS(int index) throws Exception {
		if (index > deadlinesAndSchedules.size()) {
			throw new Exception(
					RETURN_CODES_IN_ENGLISH[ERR_INDEX_OUT_OF_BOUNDS]);
		}
		return deadlinesAndSchedules.get(index);
	}

	public static Floating getFT(int index) {
		return floatingTasks.get(index);
	}

	public static LinkedList<Deadline> getDeadlinesAndSchedules() {
		return deadlinesAndSchedules;
	}

	public static LinkedList<Floating> getFloatingTasks() {
		return floatingTasks;
	}

	public static int setDataSource(Data pointerToData) {
		if (pointerToData == null) {
			return 1;
		}
		internalData = pointerToData;
		return 0;
	}

	public static boolean isFloatingListChanged() {
		return floatingListChanged;
	}

	public static boolean isDeadlineListChanged() {
		return deadlineListChanged;
	}

	/**
	 * This method checks the status and action codes and determines how to
	 * update the <I>floatingTasks</I> and <I>deadlinesAndSchedules</I>
	 * lists
	 */
	public static void update() {

		if (actionCode == ACTION_UPDATE_FT) {
			switch (statusCode) {
			case (STATUS_SHOW_SEARCH):
				floatingTasks = internalData.getFloatingTasks(searchString);
				break;

			case (STATUS_SHOW_DATE):
				floatingTasks = internalData.getFloatingTasks(date);
				break;
			case (STATUS_SHOW_CURRENT):
				floatingTasks = internalData.getFloatingTasks();
				break;
			case (STATUS_SHOW_DATE_RANGE):
				floatingTasks = internalData.getFloatingTasks(Date.getListDates(
						start, end));
				break;
			case (STATUS_SHOW_ARCHIVE):
				floatingTasks = internalData.getFloatingArchive();
				break;
			case (STATUS_SHOW_SEARCH_ARCHIVE):
				floatingTasks = internalData.getFloatingArchive(searchString);
				break;
			default:
				break;
			}
		} else if (actionCode == ACTION_UPDATE_DAS) {
			switch (statusCode) {
			case (STATUS_SHOW_CURRENT):
				deadlinesAndSchedules = internalData.getCurrent();
				break;
			case (STATUS_SHOW_ARCHIVE):
				deadlinesAndSchedules = internalData.getArchive();
				break;
			case (STATUS_SHOW_DATE):
				deadlinesAndSchedules = internalData
						.getDeadlinesAndSchedules(date);
				break;
			case (STATUS_SHOW_DATE_RANGE):
				deadlinesAndSchedules = internalData
						.getDeadlinesAndSchedules(Date.getListDates(start, end));
				break;
			case (STATUS_SHOW_SEARCH):
				deadlinesAndSchedules = internalData
						.getDeadlinesAndSchedules(searchString);
				break;
			case (STATUS_SHOW_SEARCH_ARCHIVE):
				deadlinesAndSchedules = internalData.getArchive(searchString);
				break;
			default:
				break;
			}
		} else if (actionCode == ACTION_UPDATE_ALL) {
			switch (statusCode) {
			case (STATUS_SHOW_CURRENT):
				deadlinesAndSchedules = internalData.getCurrent();
				floatingTasks = internalData.getFloatingTasks();
				break;
			case (STATUS_SHOW_ARCHIVE):
				deadlinesAndSchedules = internalData.getArchive();
				floatingTasks = internalData.getFloatingArchive();
				break;
			case (STATUS_SHOW_DATE):
				deadlinesAndSchedules = internalData
						.getDeadlinesAndSchedules(date);
				floatingTasks = internalData.getFloatingTasks(date);
				break;
			case (STATUS_SHOW_DATE_RANGE):
				LinkedList<Date> list = Date.getListDates(start, end);
				deadlinesAndSchedules = internalData
						.getDeadlinesAndSchedules(list);
				floatingTasks = internalData.getFloatingTasks(list);
				break;
			case (STATUS_SHOW_SEARCH):
				deadlinesAndSchedules = internalData
						.getDeadlinesAndSchedules(searchString);
				floatingTasks = internalData.getFloatingTasks(searchString);
				break;
			case (STATUS_SHOW_SEARCH_ARCHIVE):
				deadlinesAndSchedules = internalData.getArchive(searchString);
				floatingTasks = internalData.getFloatingArchive(searchString);
				break;
			case (STATUS_SHOW_SEARCH_TAGS):
				deadlinesAndSchedules = internalData.getTaggedDeadlinesAndSchedules(searchString);
				floatingTasks = internalData.getTaggedFloatingTasks(searchString);
			default:
				break;
			}
		}
	}

	public static void addMessage(String string) {
		messages.offer(string);
	}

	public static void setStatus(int status) {
		statusCode = status;
	}

	public static void setAction(int action) {
		actionCode = action;
	}

	public static void setSearchString(String search) {
		searchString = search;
	}

	public static void setStartDate(Date date) {
		start = date;
	}

	public static void setDate(Date date) {
		ParserReturnObject.date = date;
	}

	public static void setEndDate(Date date) {
		end = date;
	}

	public static void setFloatingListChanged(boolean floatingListChanged) {
		ParserReturnObject.floatingListChanged = floatingListChanged;
	}

	public static void setDeadlineListChanged(boolean deadlineListChanged) {
		ParserReturnObject.deadlineListChanged = deadlineListChanged;
	}

	public static Queue<String> getQueue() {
		return messages;
	}

	public static int getStatus() {
		return statusCode;
	}
	
	public static Date getDate() {
		return date;
	}

	/**
	 * This method performs the function of updating the <I>deadlinesAndSchedules</I> 
	 * and <I>floatingTasks</I> when the Home button is pressed
	 */
	public static void buttonHome() {
		actionCode = ACTION_UPDATE_ALL;
		statusCode = STATUS_SHOW_CURRENT;
		update();
		setListChanged();
	}

	/**
	 * This method performs the function of updating the <I>deadlinesAndSchedules</I> 
	 * and <I>floatingTasks</I> to display the tasks on the date
	 * 
	 * @param date
	 */
	public static void buttonDate(Date date) {
		ParserReturnObject.date = date;
		actionCode = ACTION_UPDATE_ALL;
		statusCode = STATUS_SHOW_DATE;
		update();
		setListChanged();
	}

	/**
	 * This method performs the function of updating the <I>deadlinesAndSchedules</I> 
	 * and <I>floatingTasks</I> when the Archive button is pressed
	 */
	public static void buttonArchive() {
		actionCode = ACTION_UPDATE_ALL;
		statusCode = STATUS_SHOW_ARCHIVE;
		update();
		setListChanged();
	}

	/**
	 * This method determines if <I>deadlinesAndSchedules</I> and <I>floatingTasks</I>
	 * has changed
	 */
	public static void setListChanged() {
		switch (actionCode) {
		case ACTION_UPDATE_ALL:
			floatingListChanged = true;
			deadlineListChanged = true;
			break;
		case ACTION_UPDATE_DAS:
			deadlineListChanged = true;
			break;
		case ACTION_UPDATE_FT:
			floatingListChanged = true;
			break;
		default:
			break;
		}
	}

	/**
	 * This method stores the previous values of the status and action codes
	 * to be loaded in the event of an unexpected exception
	 */
	public static void saveContext() {
		statusCodeContext = statusCode;
		actionCodeContext = actionCode;
	}

	/**
	 * This method loads the saved values of the status and action codes
	 * in the event of an unexpected exception
	 */
	public static void loadContext() {
		actionCode = actionCodeContext;
		statusCode = statusCodeContext;
	}
}
